#define RGB_Num 34  //the numbers of leds

/*
 * function:XPoint_YCricle. 一点-八点。点数
 * offset: the offset(index) led in led line. keep it at positive
 * gaps:  the numbers of off-led in a cricle. In the video it shows 2
 * points: the numbers of on-led in a cricle. set 1 to 8 to realize 1 pixel 一点三圈, 2 pixel 两点三圈...8 pixel 八点三圈
 * color:  the color set to on-led
 * call example:
gobal int Index = 0;
void main(){
    ...
    leds_driver();
    ...
    while(1){
        OnePoint_3Cricle(Index, 2, 0xff0000);//0xff0000 equ to red(rgb)
        delay_ms(500);
        Index++;
    }
}
*/
void XPoint_YCricle(int offset, int gaps, int points, PIXEL_TYPE color){
  offset = offset % (gaps + points);
  int i = 0;
  for (; (i + gaps) < offset; i++){//light leds before offset
    leds[i] = color;
  }
  for (; i < offset; i++){//off leds before offset
    leds[i] = 0;
  }
  for (; i < RGB_Num; i++){//ctrl leds after offset
    for (int j = 0; j < points; j++){ //light leds after next cricle
      leds[i] = color;
      i++;
    }
    for (int j = 0; j < gaps; j++){//off leds after next cricle
      leds[i] = 0;
      i++;
    }
  }
  theRGBLine_show();  //show led line, you should call your own implemention
}


/*
 * function:Simple_Marquee.跑马灯
 * offset: the offset(index) led in led line. keep it at positive
 * points: the numbers of on-led in a Marquee. 
 * color:  the color set to on-led
 * call example:
gobal int Index = 0;
void main(){
    ...
    leds_driver();
    ...
    while(1){
        Simple_Marquee(Index, 7, 0xff0000);//0xff0000 equ to red(rgb)
        delay_ms(200);
        Index++;
    }
}
*/
void Simple_Marquee(int offset, int points, PIXEL_TYPE color){//跑马灯
  offset = offset % RGB_Num;
  int i = 0;
  for (; (i + points) <= offset; i++){
    leds[i] = 0;
  }
  for (; i <= offset; i++){
    leds[i] = color;
  }
  for (; i < RGB_Num; i++){
    leds[i] = 0;
  }
  theRGBLine_show();  //show led line, you should call your own implemention
}

/*
 * function:Mutil_Marquee.高密度跑马灯
 * offset: the offset(index) led in led line. keep it at positive
 * gaps:  the numbers of off-led in a Marquee.
 * points: the numbers of on-led in a Marquee. 
 * color:  the color set to on-led
 * call example:
gobal int Index = 0;
void main(){
    ...
    leds_driver();
    ...
    while(1){
        Mutil_Marquee(Index, 4, 7, 0xff0000);//0xff0000 equ to red(rgb)
        delay_ms(200);
        Index++;
    }
}
*/
void Mutil_Marquee(int offset, int gaps, int points, PIXEL_TYPE color){ //高密度跑马灯
  offset = offset % (gaps + points);
  int i = 0;
  for (; (i + gaps) < offset; i++){//light leds before offset
    leds[i] = color;
  }
  for (; i < offset; i++){//off leds before offset
    leds[i] = 0;
  }
  for (; i < RGB_Num; i++){//ctrl leds after offset
    for (int j = 0; j < points; j++){ //light leds after next cricle
      leds[i] = color;
      i++;
    }
    for (int j = 0; j < gaps; j++){//off leds after next cricle
      leds[i] = 0;
      i++;
    }
  }
  theRGBLine_show();  //show led line, you should call your own implemention
}

/*
 * function:Simple_Center_Marquee.居中跑马灯
 * offset: the offset(index) led in led line. keep it at positive
 * points: the numbers of on-led in a Marquee. 
 * color:  the color set to on-led
 * call example:
gobal int Index = 0;
void main(){
    ...
    leds_driver();
    ...
    while(1){
        Simple_Center_Marquee(Index, 7, 0xff0000);//0xff0000 equ to red(rgb)
        delay_ms(200);
        Index++;
    }
}
*/
#define Marquee_Points 8
void Simple_Center_Marquee(int offset, int points, PIXEL_TYPE color){
  static uint32_t colorBak = 0;
  int CenterPoint = (RGB_Num - 1) >> 1;
  int TotalNum = (CenterPoint + 1) << 1;
  offset = offset % (CenterPoint + points + 1);

  int i = 0;
  for (; (i + points) <= offset; i++){
    leds[i] = 0;
    leds[TotalNum - i -1] = 0;
  }
  int cIdx = 0;
  for (; i <= offset; i++){
    int j = TotalNum - i -1;
    if(offset < points){
      leds[i] = color;
      leds[j] = color;
    }
    else if(i <= CenterPoint){
      leds[i] = color;
      leds[j] = color;
    }
    cIdx++;
  }
  theRGBLine_show();  //show led line, you should call your own implemention
}

/*
 * function:Mutil_Center_Marquee.高密度居中跑马灯
 * offset: the offset(index) led in led line. keep it at positive
 * gaps:  the numbers of off-led in a Marquee.
 * points: the numbers of on-led in a Marquee. 
 * color:  the color set to on-led
 * call example:
gobal int Index = 0;
void main(){
    ...
    leds_driver();
    ...
    NextCricle = false; //should be called when mode changed
    while(1){
        Mutil_Center_Marquee(Index, 4, 7, 0xff0000);//0xff0000 equ to red(rgb)
        delay_ms(200);
        Index++;
    }
}
*/

bool NextCricle = false;
void Mutil_Center_Marquee(int offset, int gaps, int points, PIXEL_TYPE color){//高密度居中跑马
  static uint32_t colorBak = 0;
  int CenterPoint = (RGB_Num - 1) >> 1;
  int TotalNum = (CenterPoint + 1) << 1;
  int finalPoint = CenterPoint + points;
  if(offset > finalPoint) NextCricle = true;
  if(NextCricle){
    if (offset <= finalPoint){
      if(offset <= (CenterPoint+1)%(gaps+points)+points)
        offset = CenterPoint + offset;
      else
        offset = offset + CenterPoint;
    }
    if(offset > finalPoint){
      offset = (offset - finalPoint - 1) % (gaps + points) + (CenterPoint - gaps + 1);
    }
  }
  else{
    offset = offset % (finalPoint + 1);
  }
  int totalCricle = (offset + 1) / (gaps + points); //整圈数量
  int restNum = (offset + 1) % (gaps + points);     //余数

  for (int i = 0; i < totalCricle; i++){
    for (int j = 0; j < points; j++){
      int k = TotalNum - offset - 1;
      if(offset <= CenterPoint){
        leds[offset] = color;
        leds[k] = color;
      }
      offset--;
    }
    for (int j = 0; j < gaps; j++){
      int k = TotalNum - offset - 1;
      leds[offset] = 0;
      leds[k] = 0;
      if(offset==0) break;
      offset--;
    }
  }
  for (int i = 0; i < restNum; i++){
    int k = TotalNum - offset - 1;
    if(i < points){
      leds[offset] = color;
      leds[k] = color;
    }
    else{
      leds[offset] = 0;
      leds[k] = 0;
    }
    offset--;
  }
  theRGBLine_show();  //show led line, you should call your own implemention
}

/*
 * function:Random_Flash.慢闪-乱闪
 * points: the numbers of on-led in a led line. 
 * color:  the color set to on-led
 * call example:
void main(){
    ...
    randomSeed(ad_value_or_other);//create random seed
    leds_driver();
    ...
    while(1){
        Random_Flash(Index, 4, 7, 0xff0000);//0xff0000 equ to red(rgb)
        delay_ms(100);// fast flash
        //delay_ms(700);// slow flash
    }
}
*/
void Random_Flash(int points, PIXEL_TYPE color){//随机慢闪、乱闪
    theRGBLine_clear(); // you should call your own implemention, clear leds[] array
    for (int i = 0; i < points;)
    {
      int k = random(0, RGB_Num);
      if (leds[k] == 0)
      {
        leds[k] = color;
        i++;
      }
    }
    theRGBLine_show();
}

/*
 * function:Fill_Color.填满--填空
 * points: the numbers to fill when it is called. 
 * color:  the color set to on-led
 * call example:
void main(){
    ...
    randomSeed(ad_value_or_other);//create random seed
    leds_driver();
    ...
    Fill_Init(0); //should be called when changed from other mode-填满
    while(1){
        if(Fill_Color(2, 0xff0000)) break;//when return true, means fill/clear had finished
        delay_ms(200);
    }
    ...
    Fill_Init(0x0f0f00); //should be called when changed from other mode-填空
    while(1){
        if(Fill_Color(2, 0)) break;//when return true, means fill/clear had finished
        delay_ms(200);
    }
    ...
}
*/

#define FILL_MAX_POINTS 20
int startArray[FILL_MAX_POINTS] = {0};//seed array    
int resultArray[FILL_MAX_POINTS] = {0};//random array    
bool Fill_Color_Init = true;  // should set true when first time call Fill_Color fun

void Fill_Init(PIXEL_TYPE fillcolor){
  Fill_Color_Init = true;
  theRGBLine_fill(fillcolor);  // you should call your own implemention, clear leds[] array
  theRGBLine_show();  // you should call your own implemention
}

bool Fill_Color(int points, PIXEL_TYPE color){//true means fill cell finish，填空，填满
  int totalCricle = RGB_Num/points;
  int restNum = RGB_Num % points;
  static int resultIdx = 0;
  if(Fill_Color_Init){    //create random array
    Fill_Color_Init = false;
    for (int i = 0; i < points; i++)
    {
      startArray[i] = i;
    }
    for(int i = 0; i < points; i++){
      int seed = random(0, points - i);
      resultArray[i] = startArray[seed];//save random result without repeat
      startArray[seed] = startArray[points - i - 1];
    }
    if(color){
      theRGBLine_clear(); // you should call your own implemention, clear leds[] array
    }
    else{
      theRGBLine_fill(0xff0000); // you should call your own implemention, fill leds[] array with color or 0xff0000
    }
    theRGBLine_show();
    return Fill_Color_Init;
  }

  int i=0;
  for(;i<totalCricle;i++){
    leds[resultArray[resultIdx]+points*i] = color;
  }
  if(restNum>resultArray[resultIdx]){
    leds[totalCricle*points+resultArray[resultIdx]] = color;
  }
  resultIdx++;
  if(resultIdx>=points){
    Fill_Color_Init = true;
    resultIdx = 0;
  }

  theRGBLine_show();
  return Fill_Color_Init;//return true means fill fully, otherwise you should keep calling this fun
}
